/*
 * Copyright 2008 Neil Bacon
 * Distributed under the terms of the Mozilla Public License version 1.1
 * or the GNU General Public License version 3.
 */

package nb.xadd.node.impl;

import java.util.Arrays;

import nb.xadd.node.Node;
import nb.xadd.operator.BinaryOperator;

public class LinearValueNode extends AbstractValueNode {

    private double[] coeff;
    private final int hashCode;

    protected LinearValueNode(double constValue, double[] coeff) {
        super(constValue);
        this.coeff = coeff;
        hashCode = calcHashCode();
    }

    @Override
    public int hashCode() {
        return hashCode;
    }

    protected int calcHashCode() {
        final int prime = 31;
        int result = super.calcHashCode();
        result = prime * result + Arrays.hashCode(coeff);
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (!super.equals(obj))
            return false;
        LinearValueNode other = (LinearValueNode) obj;
        return Arrays.equals(coeff, other.coeff);
    }

    @Override
    public Ordering getOrdering() {
        return Ordering.LINEAR;
    }

    /**
     * Get immutable coefficients.
     * @return linear coefficients
     */
    public double[] getCoeff() {
        return coeff;
    }

    /**
     * Get mutable copy of coefficients.
     * @return linear coefficients
     */
    public double[] getCopyOfCoeff() {
        return Arrays.copyOf(coeff, coeff.length);
    }

    // Don't care about ordering of one LinearValueNode w.r.t. another.
    //	@Override
    //	public int compareTo(Node other) {
    //		int i = super.compareTo(other);
    //		if (i != 0) return i;
    //		LinearValueNode n = (LinearValueNode) other;
    //		i =  Double.compare(getConstValue(), n.getConstValue());
    //		if (i != 0) return i;
    //		i = coeff.length - n.coeff.length;
    //		for (int j = 0; i == 0 && j < coeff.length; j++) {
    //			i = Double.compare(coeff[i], n.coeff[i]);
    //		}
    //		return i;
    //	}

    @Override
    public int getPolynomialOrder() {
        return 1;
    }

    @Override
    public Node apply(BinaryOperator binaryOperator, Node node) {
        return node.applyLinearValue(binaryOperator, this);
    }

    @Override
    public Node applyConstantValue(BinaryOperator binaryOperator, ConstantValueNode node) {
        return binaryOperator.executeConstantLinear(node, this);
    }

    @Override
    public Node applyLinearValue(BinaryOperator binaryOperator, LinearValueNode node) {
        return binaryOperator.executeLinearLinear(this, node);
    }

    @Override
    public Node applyPolynomialValue(BinaryOperator binaryOperator, PolynomialValueNode node) {
        return binaryOperator.executeLinearPolynomial(this, node);
    }

    @Override
    public Node applyBooleanDecision(BinaryOperator binaryOperator, BooleanDecisionNode node) {
        return binaryOperator.executeLinearBooleanDecision(this, node);
    }

    @Override
    public Node applyRealEqualDecision(BinaryOperator binaryOperator, RealEqualDecisionNode node) {
        return binaryOperator.executeLinearRealEqualDecision(this, node);
    }

    @Override
    public Node applyRealGreaterOrEqualDecision(BinaryOperator binaryOperator, RealGreaterOrEqualDecisionNode node) {
        return binaryOperator.executeLinearRealGreaterOrEqualDecision(this, node);
    }

    @Override
    public void appendTo(int depth, StringBuilder buf) {
        super.appendTo(depth, buf);
        buf.append(", linear coeff = ").append(Arrays.toString(coeff)).append("\n");
    }

}
